#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

#include "MSTK.h"


#ifdef __cplusplus
extern "C" {
#endif

  /* 
     This function concatenates submeshes into the global mesh.
     Also attrib list is constructed in mesh.
     
     GEntID, GEntDim and MasterParID will be retained in mesh for
     vertex and faces.
     
     Caller should allocate memory for mesh: 
     Mesh_ptr mesh = MESH_New(type);
  */
int        MESH_Surf_Concatenate(Mesh_ptr mesh, Mesh_ptr *submeshes, int num);
int        MESH_Vol_Concatenate(Mesh_ptr mesh, Mesh_ptr *submeshes, int num);

int MESH_Concatenate(Mesh_ptr mesh, Mesh_ptr *submeshes, int num) {
  int j, nf, nr, natt, ncomp;
  char attname[256];
  MType mtype;
  MAttType att_type;
  MAttrib_ptr attrib;
  RepType rtype = MESH_RepType(submeshes[0]);

  MESH_SetRepType(mesh,rtype);

  /* basic mesh information */
  nf = MESH_Num_Faces(submeshes[0]);
  nr = MESH_Num_Regions(submeshes[0]);
  if(nr)
    MESH_Vol_Concatenate(mesh,submeshes,num);
  else if (nf)
    MESH_Surf_Concatenate(mesh,submeshes,num);
  else {
    MSTK_Report("MESH_Concatenate()","This is not a valid mstk file for partition",ERROR);
    exit(-1);
  }


  /* assign attrib list */
  natt = MESH_Num_Attribs(submeshes[0]);
  for(j = 0; j < natt; j++) {
    attrib = MESH_Attrib(submeshes[0],j);
    MAttrib_Get_Name(attrib,attname);
    /* see of the attrib exists */
    if(MESH_AttribByName(mesh,attname))
      continue;
    att_type = MAttrib_Get_Type(attrib);
    ncomp = MAttrib_Get_NumComps(attrib);
    mtype = MAttrib_Get_EntDim(attrib);
    if(ncomp == 1)
      attrib =  MAttrib_New(mesh, attname, att_type, mtype);
    else
      attrib =  MAttrib_New(mesh, attname, att_type, mtype, ncomp);
  }

  return 1;
}

int MESH_Surf_Concatenate(Mesh_ptr mesh, Mesh_ptr *submeshes, int num) {
  int i, j, idx;
  int nv, nfv;
  MVertex_ptr mv, *verts, *fverts, *mfverts;
  MFace_ptr mf, global_mf;

  /* basic mesh information */
  nv = 0;
  for(i = 0; i < num; i++) 
    nv += MESH_Num_Vertices(submeshes[i]);

  verts = (MVertex_ptr *) MSTK_malloc(nv*sizeof(MVertex_ptr));
  fverts = (MVertex_ptr *) MSTK_malloc(MAXPV2*sizeof(MVertex_ptr));


  for(i = 0; i < num; i++) {
    idx = 0;
    /* add vertex */
    while( mv = MESH_Next_Vertex(submeshes[i],&idx) ) {
      if(MV_MasterParID(mv) != i)
	continue;
      verts[MV_GlobalID(mv)-1] = MV_New(mesh);
      PMV_Duplicate(mv,verts[MV_GlobalID(mv)-1]);
    }
    idx = 0;
    /* add face */
    while( mf = MESH_Next_Face(submeshes[i],&idx) ) {
      if(MF_MasterParID(mf) != i)
	continue;
      global_mf = MF_New(mesh);
      mfverts = MF_Vertices(mf,1,0);
      nfv = List_Num_Entries(mfverts);
      for(j = 0; j < nfv; j++)
	fverts[j] = verts[MV_GlobalID(List_Entry(mfverts,j))-1];
      MF_Set_Vertices(global_mf,nfv,fverts);
      PMF_Duplicate(mf,global_mf);
      List_Delete(mfverts);
    }
  }
  MSTK_free(fverts);
  MSTK_free(verts);
  return 1;
}


int MESH_Vol_Concatenate(Mesh_ptr mesh, Mesh_ptr *submeshes, int num) {
  int i, j, idx;
  int nv, nrv;
  MVertex_ptr mv, *verts, *rverts, *mrverts;
  MRegion_ptr mr, global_mr;

  /* basic mesh information */
  nv = 0;
  for(i = 0; i < num; i++) 
    nv += MESH_Num_Vertices(submeshes[i]);

  verts = (MVertex_ptr *) MSTK_malloc(nv*sizeof(MVertex_ptr));
  rverts = (MVertex_ptr *) MSTK_malloc(MAXPV3*sizeof(MVertex_ptr));


  for(i = 0; i < num; i++) {
    idx = 0;
    /* add vertex */
    while( mv = MESH_Next_Vertex(submeshes[i],&idx) ) {
      if(MV_MasterParID(mv) != i)
	continue;
      verts[MV_GlobalID(mv)-1] = MV_New(mesh);
      PMV_Duplicate(mv,verts[MV_GlobalID(mv)-1]);
    }
    idx = 0;
    /* add region */
    while( mr = MESH_Next_Region(submeshes[i],&idx) ) {
      if(MR_MasterParID(mr) != i)
	continue;
      global_mr = MR_New(mesh);
      mrverts = MR_Vertices(mr);
      nrv = List_Num_Entries(mrverts);
      for(j = 0; j < nrv; j++)
	rverts[j] = verts[MV_GlobalID(List_Entry(mrverts,j))-1];
      MR_Set_Vertices(global_mr,nrv,rverts,0,NULL);
      PMR_Duplicate(mr,global_mr);
      List_Delete(mrverts);
    }
  }
  MSTK_free(rverts);
  MSTK_free(verts);
  return 1;
}

  
#ifdef __cplusplus
}
#endif

